#include "stdafx.h"
#include "IOCPBuffer.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CIOCPBuffer::CIOCPBuffer()
{
    Init(); // Never called if the class is allocated with VirtualAlloc.. 	
}

void CIOCPBuffer::Init()
{
    m_nUsed=0;
    m_Operation=-1;
    m_pPos=NULL;
    ZeroMemory(&m_ol, sizeof(OVERLAPPED));
    ZeroMemory(&m_Buffer,sizeof(m_Buffer));
}


CIOCPBuffer::~CIOCPBuffer()
{
    // Never called if the class is allocated with VirtualAlloc.. 
    m_nUsed=0;
    //FreeBuffer();
}



/*
* Returns the pointer to the Buffer.  
*
*/
PBYTE CIOCPBuffer::GetBuffer()
{
    return (PBYTE)m_Buffer;
}

PBYTE CIOCPBuffer::GetPayLoadBuffer()
{
    return m_nUsed>MINIMUMPACKAGESIZE ? GetBuffer()+MINIMUMPACKAGESIZE : NULL;	
}

/*
* Adds a singel BYTE to the data. 
*
*/

BOOL CIOCPBuffer::AddData(BYTE data)
{
    return AddData(&data, 1);
}

BOOL CIOCPBuffer::AddData(UINT data)
{
    return AddData(reinterpret_cast<const BYTE*>(&data), sizeof(UINT));
}


BOOL CIOCPBuffer::AddData(unsigned short data)
{
    return AddData(reinterpret_cast<const BYTE*>(&data), sizeof(unsigned short));
}


/*
* Adds a stream of char to the buffer. 
*
*/
BOOL CIOCPBuffer::AddData(const char *const pData, UINT nSize)
{ 
    return AddData(reinterpret_cast<const BYTE*>(pData),nSize);
}

/*
* Adds a stream of BYTES to the buffer. 
*
*/

BOOL CIOCPBuffer::AddData(const BYTE *const pData, UINT nSize)
{
    if ( nSize > MAXIMUMPACKAGESIZE-m_nUsed )
        return FALSE;
    else
    {
        memcpy(m_Buffer + m_nUsed, pData, nSize);
        m_nUsed += nSize;
        return TRUE;
    }
}


// cheks if the Buffer is valid. 
BOOL CIOCPBuffer::IsValid()
{
    return TRUE;
}

UINT CIOCPBuffer::GetUsed()
{
    return m_nUsed;
}

// Used to indicate that we did have  a successfull Receive 
UINT CIOCPBuffer::Use(UINT nSize)
{
    m_nUsed+=nSize;
    return m_nUsed;
}

// Empty A used structure. 
void CIOCPBuffer::EmptyUsed()
{
    m_nUsed=0;
}

// Sets the current Operation. 
void CIOCPBuffer::SetOperation(int op)
{
    ZeroMemory(&m_ol, sizeof(OVERLAPPED));
    m_Operation=op;
}


// Setup the buffer for a ZeroByteRead. 
void CIOCPBuffer::SetupZeroByteRead()
{
    m_wsabuf.buf =(char*)m_Buffer;
    m_wsabuf.len = 0; 
}

// Setup Setup the buffer for a Read. 
void CIOCPBuffer::SetupRead()
{
    if (m_nUsed == 0)
    {
        m_wsabuf.buf = reinterpret_cast<char*>(m_Buffer);
        m_wsabuf.len = MAXIMUMPACKAGESIZE; 
    }
    else // We have received some of the data but not all .. 
    {
        m_wsabuf.buf = reinterpret_cast<char*>(m_Buffer) + m_nUsed;
        m_wsabuf.len = MAXIMUMPACKAGESIZE - m_nUsed; 
    }
}

// Setup the buffer for a Write
void CIOCPBuffer::SetupWrite()
{
    m_wsabuf.buf = reinterpret_cast<char*>(m_Buffer);
    m_wsabuf.len = m_nUsed;
}

// Returns the WSABUF used with WsaRead and WsaWrite. 
WSABUF * CIOCPBuffer::GetWSABuffer()
{
    return  const_cast<WSABUF*>(&m_wsabuf);
}

//Get the Operation 
int CIOCPBuffer::GetOperation()
{
    return m_Operation;
}

// Saves a position into the buffer (e.g. in a CList) 
void CIOCPBuffer::SetPosition(POSITION pos)
{
    m_pPos=pos;
}

// Returns the Position of a buffer. 
POSITION CIOCPBuffer::GetPosition()
{
    return m_pPos;
}


// removes nSize byte from the Buffer. 
BOOL CIOCPBuffer::Flush(UINT nBytesToRemove)
{
    if ((nBytesToRemove > MAXIMUMPACKAGESIZE) || (nBytesToRemove > m_nUsed) ) 
    {
        TRACE("ERROR BOOL CIOCPBuffer::Flush(UINT nBytesToRemove)");
        return FALSE;
    }
    m_nUsed-=nBytesToRemove;
    memmove(m_Buffer, m_Buffer + nBytesToRemove, m_nUsed);
    return TRUE;
}



// Sets the sequence number of the buffer..
void CIOCPBuffer::SetSequenceNumber(int nr)
{
    m_iSequenceNumber=nr;
}


// Gets the sequence number of the buffer. 
int CIOCPBuffer::GetSequenceNumber()
{
    return m_iSequenceNumber;
}


/*
* CreatePackage(CString stxt)
* Creates one package in the buffe. (Se below) 
*
* [SizeHeader|...String..\0]
*/

BOOL CIOCPBuffer::CreatePackage(CString stxt)
{
    UINT nBufLen = stxt.GetLength();	
    if(nBufLen<MAXIMUMPACKAGESIZE-MINIMUMPACKAGESIZE&&nBufLen>0)
    {
        // Perpare Package. 
        // Empty the Buffer..
        EmptyUsed();
        // Add one to the size header for the null termination byte. 
        nBufLen++;
        // Add The Header
        AddData(nBufLen);
        // Add the string. 
        int length=stxt.GetLength();
        AddData((PBYTE) stxt.GetBuffer(length),length);


        // Null Teriminate (for Strings) 
        BYTE nullTerm='\0';
        AddData(nullTerm);
        return TRUE;
    }
    return FALSE;
}


/*
* CreatePackage(BYTE Type,CString stxt)
* Creates one package in the buffe. (Se below) 
*
* [SizeHeader|Type|...String..\0]
*/
BOOL CIOCPBuffer::CreatePackage(BYTE Type,CString stxt)
{
    UINT nBufLen = stxt.GetLength();	
    if(nBufLen<(MAXIMUMPACKAGESIZE-MINIMUMPACKAGESIZE-1)&&nBufLen>0)
    {
        // Perpare Package. 
        // Empty the Buffer..
        EmptyUsed();

        // Add one to the size header for the null termination byte.  
        nBufLen++;

        // Add one to the size header for the Type byte. .  
        nBufLen++;

        // Add The Header
        AddData(nBufLen);

        // Add the Type. 
        AddData(Type);

        // Add the string. 
        int length=stxt.GetLength();
        AddData((PBYTE) stxt.GetBuffer(length),length);


        // Null Teriminate (for Strings) 
        BYTE nullTerm='\0';
        AddData(nullTerm);
        return TRUE;
    }
    return FALSE;
}

/*
* CreatePackage(BYTE Type,CString stxt)
* Creates one package in the buffe. (Se below) 
*
* [SizeHeader|Type|...String..\0]
*/
BOOL CIOCPBuffer::CreatePackage(BYTE Type)
{
    // Perpare Package. 
    // Empty the Buffer..
    EmptyUsed();
    // Add one to the size header for the Type byte. .  
    UINT nBufLen=1;
    // Add The Header
    AddData(nBufLen);
    // Add the Type. 
    AddData(Type);
    return TRUE;
}



/*
* CreatePackage(BYTE Type,CString stxt)
* Creates one package in the buffe. (Se below) 
*
* [SizeHeader|Type|...String..\0]
*/

BOOL CIOCPBuffer::CreatePackage(BYTE Type,UINT nData, CString stxt)
{
    UINT nBufLen = stxt.GetLength();	
    if(nBufLen<(MAXIMUMPACKAGESIZE-MINIMUMPACKAGESIZE-1-sizeof(UINT))&&nBufLen>0)
    {
        // Perpare Package. 
        // Empty the Buffer..
        EmptyUsed();

        // Add one to the size header for the null termination byte.  
        nBufLen++;

        // Add one to the size header for the Type byte. .  
        nBufLen++;

        // Add The bytes for the nSize data. 
        nBufLen+=sizeof(UINT);

        // Add The Header
        AddData(nBufLen);

        // Add the Type. 
        AddData(Type);

        //Add the size data
        AddData(nData);

        // Add the string. 
        int length=stxt.GetLength();
        AddData((PBYTE) stxt.GetBuffer(length),length);

        // Null Teriminate (for Strings) 
        BYTE nullTerm='\0';
        AddData(nullTerm);
        return TRUE;
    }
    return FALSE;
}

/*
* CreatePackage(BYTE Type, BYTE key, CString stxt)
* Creates one package in the buffe. (Se below) 
*
* [SizeHeader|Type|Key|...String..\0]
*/
BOOL CIOCPBuffer::CreatePackage(BYTE Type, BYTE key, CString stxt)
{
    UINT nBufLen = stxt.GetLength();	
    if(nBufLen<(MAXIMUMPACKAGESIZE-MINIMUMPACKAGESIZE-2))
    {
        // Perpare Package. 
        // Empty the Buffer..
        EmptyUsed();

        // Add one to the size header for the null termination byte.  
        nBufLen++;

        // Add one to the size header for the Type byte. .  
        nBufLen++;

        // Add one to the size header for the key. .  
        nBufLen++;

        // Add The Header
        AddData(nBufLen);

        // Add the Type. 
        AddData(Type);

        //Add the key data
        AddData(key);


        // Add the string. 
        int length=stxt.GetLength();
        if(length>0)
            AddData((PBYTE) stxt.GetBuffer(length),length);

        // Null Teriminate (for Strings) 
        BYTE nullTerm='\0';
        AddData(nullTerm);
        return TRUE;
    }
    return FALSE;
}


/*
* CreatePackage(BYTE Type,BYTE key1, BYTE key2, BYTE key3,CString stxt)
* Creates one package in the buffe. (Se below) 
*
* [SizeHeader|Type|Key1|key2|key3|...String..\0]
*/
BOOL CIOCPBuffer::CreatePackage(BYTE Type, BYTE key1, BYTE key2, BYTE key3, CString stxt)
{
    UINT nBufLen = stxt.GetLength();	
    if(nBufLen<(MAXIMUMPACKAGESIZE-MINIMUMPACKAGESIZE-4))
    {
        // Perpare Package. 
        // Empty the Buffer..
        EmptyUsed();

        // Add one to the size header for the null termination byte.  
        nBufLen++;

        // Add one to the size header for the Type byte. .  
        nBufLen++;

        // Add four to the size header for the Keys. .  
        nBufLen+=3;


        // Add The Header
        AddData(nBufLen);

        // Add the Type. 
        AddData(Type);

        //Add the keys data
        AddData(key1);
        AddData(key2);
        AddData(key3);

        // Add the string. 
        int length=stxt.GetLength();
        if(length>0)
            AddData((PBYTE) stxt.GetBuffer(length),length);

        // Null Teriminate (for Strings) 
        BYTE nullTerm='\0';
        AddData(nullTerm);
        return TRUE;
    }
    return FALSE;
}


/*
* CreatePackage(BYTE Type, UINT iFilesize,UINT iBufferSize, const BYTE *const pData)
* Creates one package in the buffe. (Se below) 
*
* [SizeHeader|Type|iFilesize|..Buffer data...]
*/

BOOL CIOCPBuffer::CreatePackage(BYTE Type, UINT iFilesize,UINT iBufferSize, const BYTE *const pData)
{
    UINT nBufLen=iBufferSize;
    if(iBufferSize<(MAXIMUMPACKAGESIZE-MINIMUMPACKAGESIZE-1-sizeof(UINT)))
    {
        // Perpare Package. 
        // Empty the Buffer..
        EmptyUsed();

        // Add one to the size header for the Type byte. .  
        nBufLen++;

        // Add The bytes for the iFilesize data. 
        nBufLen+=sizeof(UINT);

        // Add The Header
        AddData(nBufLen);

        // Add the Type. 
        AddData(Type);

        //Add the size data
        AddData(iFilesize);

        // Add the Buffer. 
        if(iBufferSize>0)
            AddData(pData,iBufferSize);
        return TRUE;
    }
    return FALSE;
}




/*
* Returns the PackageSize
*/
UINT CIOCPBuffer::GetPackageSize()
{
    UINT nSize=0;
    if(m_nUsed>=MINIMUMPACKAGESIZE)
    {

        memmove(&nSize,GetBuffer(),MINIMUMPACKAGESIZE);
    }
    return nSize;
}

// Gets the package Type return 255 if error. 
BYTE CIOCPBuffer::GetPackageType()
{
    BYTE Type= 255;
    UINT nSize=GetPackageSize();
    if ( nSize>=1 && nSize <=MAXIMUMPAYLOADSIZE) 
    {
        memmove(&Type,GetBuffer()+MINIMUMPACKAGESIZE,1);
    } 
    return Type;
}


// Reads the info from a package created with CreatePackage(CString stxt);
BOOL CIOCPBuffer::GetPackageInfo(CString &stxt)
{
    int nSize=GetPackageSize();
    if ( nSize>0 && nSize <= MAXIMUMPAYLOADSIZE)
    {
        PBYTE pData=GetBuffer()+MINIMUMPACKAGESIZE;
        // Assumes that we already have a null termination. 
        stxt=pData;
        return TRUE;		
    }
    return FALSE;
}

// Reads the info from a package created with CreatePackage(BYTE Type,CString stxt);
BOOL CIOCPBuffer::GetPackageInfo(BYTE& Type, CString &stxt)
{
    int nSize=GetPackageSize();
    if ( nSize>=1 && nSize<=MAXIMUMPAYLOADSIZE )
    {
        memmove(&Type,GetBuffer()+MINIMUMPACKAGESIZE,1);

        PBYTE pData=GetBuffer()+MINIMUMPACKAGESIZE+1;
        // Assumes that we already have a null termination. 
        stxt=pData;
        return TRUE;		
    }
    return FALSE;
}

// Reads the info from a package created with CreatePackage(BYTE Type,CString stxt);
BOOL CIOCPBuffer::GetPackageInfo(BYTE& Type,UINT& nData, CString& stxt)
{
    int nSize=GetPackageSize();
    if ( nSize>= 1+sizeof(UINT) && nSize<=MAXIMUMPAYLOADSIZE)
    {
        // Get the Type
        memmove(&Type,GetBuffer()+MINIMUMPACKAGESIZE,1);
        // Get the nSize 
        memmove(&nData,GetBuffer()+MINIMUMPACKAGESIZE+1,sizeof(UINT));
        // Get The text
        PBYTE pData=GetBuffer()+MINIMUMPACKAGESIZE+1+sizeof(UINT);
        // Assumes that we already have a null termination. 
        stxt=pData;
        return TRUE;		
    }
    return FALSE;
}



BOOL CIOCPBuffer::GetPackageInfo(BYTE &Type, BYTE &key1, BYTE &key2, BYTE &key3, CString &stxt)
{
    int nSize=GetPackageSize();
    if ( nSize>=1 && nSize<=MAXIMUMPAYLOADSIZE )
    {
        // Get the Type
        memmove(&Type,GetBuffer()+MINIMUMPACKAGESIZE,1);
        // Get the keys
        memmove(&key1,GetBuffer()+MINIMUMPACKAGESIZE+1,1);
        memmove(&key2,GetBuffer()+MINIMUMPACKAGESIZE+2,1);
        memmove(&key3,GetBuffer()+MINIMUMPACKAGESIZE+3,1);
        // Get The text
        PBYTE pData=GetBuffer()+MINIMUMPACKAGESIZE+4;
        // Assumes that we already have a null termination. 
        stxt=pData;
        return TRUE;	
    }
    return FALSE;
}


BOOL CIOCPBuffer::GetPackageInfo(BYTE &Type, BYTE &key, CString &stxt)
{
    int nSize=GetPackageSize();
    if ( nSize>=1 && nSize<=MAXIMUMPAYLOADSIZE )
    {
        // Get the Type
        memmove(&Type,GetBuffer()+MINIMUMPACKAGESIZE,1);
        // Get the keys
        memmove(&key,GetBuffer()+MINIMUMPACKAGESIZE+1,1);
        // Get The text
        PBYTE pData=GetBuffer()+MINIMUMPACKAGESIZE+2;
        // Assumes that we already have a null termination. 
        stxt=pData;
        return TRUE;	
    }
    return FALSE;
}


void CIOCPBuffer::DUMP()
{
    for(int i=0;i<GetUsed();i++)
    {
        CString txt;
        BYTE b=*(GetBuffer()+i);
        txt.Format("%d:%s;%d",i,GetBuffer()+i,b);
        TRACE("%s\r\n",txt);
    }
}


